﻿using iTextSharp.text.exceptions;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Tsp;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Una.FirmaDigital.LN.Dominio.Validaciones
{
    public class Firma
    {
        public bool ExisteArchivo(string archivosrc)
        {
            try
            {
                return System.IO.File.Exists(archivosrc);
            }
            catch (Exception ex)
            {

                throw ex;
            }

        }
        public bool ExisteDirectorio(string directoriosrc)
        {
            try
            {
                return System.IO.Directory.Exists(directoriosrc);
            }
            catch (Exception ex)
            {

                throw ex;
            }

        }

        public bool pdfTieneFirma(PdfReader pdfReader)
        {

            AcroFields acroFields = pdfReader.AcroFields;
            List<String> signatureNames = acroFields.GetSignatureNames();
            if (signatureNames.Count == 0)
            {
                return false;
            }
            return true;

        }

        public void verifSign(PdfReader pdfReader)
        {
            List<X509Certificate> kall = new List<X509Certificate>();
            foreach (System.Security.Cryptography.X509Certificates.StoreLocation storeLocation in
                    typeof(System.Security.Cryptography.X509Certificates.StoreLocation).GetEnumValues())
            {
                foreach (System.Security.Cryptography.X509Certificates.StoreName storeName in
                        typeof(System.Security.Cryptography.X509Certificates.StoreName).GetEnumValues())
                {
                    System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(storeName, storeLocation);

                    store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
                    try
                    {
                        X509CertificateParser certParser = new X509CertificateParser();

                        System.Security.Cryptography.X509Certificates.X509Certificate2Collection col = store.Certificates;
                        foreach (System.Security.Cryptography.X509Certificates.X509Certificate2 cer in col)
                        {
                            kall.Add(certParser.ReadCertificate(cer.RawData));
                        }
                    }
                    finally
                    {
                        store.Close();
                    }
                }
            }
            PdfReader reader = pdfReader;
            AcroFields af = reader.AcroFields;
            List<String> names = af.GetSignatureNames();
            for (int k = 0; k < names.Count; ++k)
            {
                String name = names[k];
                System.Console.Out.WriteLine("Signature name: " + name);
                Console.WriteLine("Signature covers whole document: " + af.SignatureCoversWholeDocument(name));
                System.Console.Out.WriteLine("Document revision: " + af.GetRevision(name) + " of " + af.TotalRevisions);
                // Start revision extraction
                using (FileStream fs = File.Create("revision_" + af.GetRevision(name) + ".pdf"))
                using (Stream rs = af.ExtractRevision(name))
                {
                    int c;
                    byte[] b = new byte[8192];
                    while ((c = rs.Read(b, 0, 8192)) > 0)
                        fs.Write(b, 0, c);
                    rs.Close();
                    fs.Close();
                }
                // End revision extraction
                iTextSharp.text.pdf.security.PdfPKCS7 pk = af.VerifySignature(name);
                DateTime cal = pk.SignDate;
                X509Certificate[] pkc = pk.Certificates;
                TimeStampToken ts = pk.TimeStampToken;
                if (!pk.IsTsp && ts != null)
                {
                    bool impr = pk.VerifyTimestampImprint();
                    System.Console.Out.WriteLine("Timestamp imprint verifies: " + impr);
                    cal = pk.TimeStampDate;
                    System.Console.Out.WriteLine("Timestamp date: " + cal);
                }
                System.Console.Out.WriteLine("Subject: " + EN.PdfPKCS7.GetSubjectFields(pk.SigningCertificate).GetField("CN"));
                System.Console.Out.WriteLine("Document modified: " + !pk.Verify());
                if (pk.IsTsp)
                {
                    bool tspCert = EN.PdfPKCS7.VerifyTimestampCertificates(pk.TimeStampToken, kall);
                    System.Console.Out.WriteLine("LTV Timestamp Certificates verifified " + tspCert);
                }
                else
                {
                    Object[] fails = EN.PdfPKCS7.VerifyCertificates(pkc, kall, null, cal);
                    if (fails == null)
                        System.Console.Out.WriteLine("Certificates verified against the KeyStore");
                    else
                    {
                        System.Console.Out.WriteLine("Certificate failed: " + fails[1]);
                    }
                    Org.BouncyCastle.Ocsp.BasicOcspResp ocsp = pk.Ocsp;
                    if (ocsp != null)
                    {

                        //ocsp.isSignatureValid(responderPK);
                        System.Console.Out.WriteLine("OCSP revocation refers to this certificate: " + pk.IsRevocationValid());
                    }
                }
                System.Console.Out.WriteLine();
            }
        }

        public bool tieneDireccionOSP(string archivopfx, string contrasena)
        {

            FileStream privateKeyStream = new FileStream(archivopfx, FileMode.Open, FileAccess.Read);
            Pkcs12Store pk12 = new Pkcs12Store(privateKeyStream, contrasena.ToCharArray());//chescojavier0610

            String alias = "";
            foreach (string al in pk12.Aliases)
            {
                if (pk12.IsKeyEntry(al) && pk12.GetKey(al).Key.IsPrivate)
                {
                    alias = al;
                    break;
                }
            }
            IList<X509Certificate> chain = new List<X509Certificate>();
            foreach (X509CertificateEntry entry in pk12.GetCertificateChain(alias))
            {
                chain.Add(entry.Certificate);
            }

            for (int i = 0; i < chain.Count; i++)
            {
                X509Certificate cert = chain[i];
                return CertificateUtil.GetOCSPURL(cert) == null;

            }
            return false;


        }

        public bool tieneDireccionCRL(string archivopfx, string contrasena)
        {

            FileStream privateKeyStream = new FileStream(archivopfx, FileMode.Open, FileAccess.Read);
            Pkcs12Store pk12 = new Pkcs12Store(privateKeyStream, contrasena.ToCharArray());//chescojavier0610

            String alias = "";
            foreach (string al in pk12.Aliases)
            {
                if (pk12.IsKeyEntry(al) && pk12.GetKey(al).Key.IsPrivate)
                {
                    alias = al;
                    break;
                }
            }
            IList<X509Certificate> chain = new List<X509Certificate>();
            foreach (X509CertificateEntry entry in pk12.GetCertificateChain(alias))
            {
                chain.Add(entry.Certificate);
            }

            for (int i = 0; i < chain.Count; i++)
            {
                X509Certificate cert = chain[i];
                return CertificateUtil.GetCRLURL(cert) == null;

            }
            return false;


        }

        public bool tieneDireccionTSA(string archivopfx, string contrasena)
        {

            FileStream privateKeyStream = new FileStream(archivopfx, FileMode.Open, FileAccess.Read);
            Pkcs12Store pk12 = new Pkcs12Store(privateKeyStream, contrasena.ToCharArray());//chescojavier0610

            String alias = "";
            foreach (string al in pk12.Aliases)
            {
                if (pk12.IsKeyEntry(al) && pk12.GetKey(al).Key.IsPrivate)
                {
                    alias = al;
                    break;
                }
            }
            IList<X509Certificate> chain = new List<X509Certificate>();
            foreach (X509CertificateEntry entry in pk12.GetCertificateChain(alias))
            {
                chain.Add(entry.Certificate);
            }

            for (int i = 0; i < chain.Count; i++)
            {
                X509Certificate cert = chain[i];
                return CertificateUtil.GetTSAURL(cert) == null;

            }
            return false;


        }


        public AcroFields obtenerAcrofieldsDocumento(string archivopdf)
        {
            PdfReader reader = new PdfReader(archivopdf);
            AcroFields af = reader.AcroFields;


            return af;
        }

        public int obtenerNumeroRevisionesDocumento(string archivopdf)
        {
            AcroFields af = obtenerAcrofieldsDocumento(archivopdf);
            return af.TotalRevisions;
        }
        public List<string> obtenerSignatureNames(AcroFields af)
        {
            return af == null ? null : af.GetSignatureNames();
        }
        public bool tieneFirmas(string pdfFile)
        {
            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);
            return names.Count > 0;
        }
        public bool tieneContraFirmas(string pdfFile)
        {
            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);
            return names.Count > 1;
        }
        public bool tieneContraFirmas2(string pdfFile)
        {
            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);
            return obtenerNumeroRevisionesDocumento(pdfFile) > 1;
        }
        public bool firmaCubreTodoElDocumento(string pdfFile)
        {

            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);
            foreach (string name in names)
            {
                return af.SignatureCoversWholeDocument(name);
            }
            return false;
        }
        public bool documentoTieneContrasena(string archivopdf)
        {
            try
            {
                PdfReader pdfReader = new PdfReader(archivopdf);
                pdfReader.Dispose();
                return false;
            }
            catch (BadPasswordException)
            {
                return true;
            }
        }
        public bool firmaVerificadabasico(string pdfFile)
        {
            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);
            foreach (string name in names)
            {
                PdfPKCS7 pk = af.VerifySignature(name);
                var cal = pk.SignDate;
                var pkc = pk.Certificates;
                return pk.Verify();
            }
            return false;
        }
        public bool firmaTimeStampVerificada(string pdfFile)
        {
            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);

            foreach (string name in names)
            {
                PdfPKCS7 pk = af.VerifySignature(name);
                return (pk.VerifyTimestampImprint());
            }

            return false;
        }
        public bool documentoFirmadoCorrectobasico(string pdfFile, Stream publicKeyStream)
        {
            var parser = new X509CertificateParser();
            var certificate = parser.ReadCertificate(publicKeyStream);
            publicKeyStream.Dispose();
            AcroFields af = obtenerAcrofieldsDocumento(pdfFile);
            var names = obtenerSignatureNames(af);

            foreach (string name in names)
            {
                PdfPKCS7 pk = af.VerifySignature(name);
                var cal = pk.SignDate;
                var pkc = pk.Certificates;
                IList<VerificationException> fails = CertificateVerification.VerifyCertificates(pkc, new X509Certificate[] { certificate }, null, cal);
                if (fails != null && fails.Count > 0)
                {
                    return false;
                }
            }
            return true;
        }

        public bool documentoTieneFirmasVacias(string archivopdf)
        {
            AcroFields af = obtenerAcrofieldsDocumento(archivopdf);
            List<string> blanks = af.GetBlankSignatureNames();
            return (blanks != null) && (blanks.Count > 0);
        }

        public int obtenerNumeroFirmasVacias(string archivopdf)
        {
            AcroFields af = obtenerAcrofieldsDocumento(archivopdf);
            List<string> blanks = af.GetBlankSignatureNames();
            if ((blanks != null) && (blanks.Count > 0))
            {
                return blanks.Count;
            }
            return 0;
        }

    }
}